package org.sixtynine.stock.service.file;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.sixtynine.stock.Constants;
import org.sixtynine.stock.ReturnData;
import org.sixtynine.stock.entity.BaseEntity;
import org.sixtynine.stock.entity.MonthlySectorData;
import org.sixtynine.stock.entity.Sector;
import org.sixtynine.stock.entity.WeeklySectorData;
import org.sixtynine.stock.entity.WeeklyShareData;
import org.sixtynine.stock.service.GenericService;
import org.sixtynine.stock.service.business.StockUtil;
import org.sixtynine.stock.util.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author Thilan
 * 
 */
@Component(ExcelProcessorFactory.FILE_TYPE_WEEKLY_SECTOR_DATA_LIST)
public class WeeklySectorDataListProcesser extends CompanyDataListProcessor {

	Date formatedDate;

	@Autowired
	GenericService genericService;

	private static Map<String, WeeklySectorData> exsistingSectorDataMap;

	public static String getDataString(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);

		return (calendar.get(Calendar.YEAR) + "_"
				+ (calendar.get(Calendar.MONTH) + 1) + "_" + calendar
					.get(Calendar.DATE));
	}

	private static void processExsistingRecords(List<BaseEntity> dataList) {
		exsistingSectorDataMap = new HashMap<String, WeeklySectorData>();

		Calendar caledar = Calendar.getInstance();
		for (BaseEntity baseEntity : dataList) {
			WeeklySectorData weeklySectorData = (WeeklySectorData) baseEntity;
			exsistingSectorDataMap.put(weeklySectorData.getSector().getCode(),
					weeklySectorData);

		}
	}

	@Override
	public ReturnData<List<? extends BaseEntity>> process(String filePath) {
		ReturnData<List<? extends BaseEntity>> returnData = new ReturnData<List<? extends BaseEntity>>(
				Constants.SUCCESS, "");

		// initialized if maps are not created
		if (sectorMap == null && subSectorMap == null) {
			init();
		}

		try {

			List<BaseEntity> weeklySectorDataList = new ArrayList<BaseEntity>();

			File file = new File(filePath);

			// Get the workbook instance for XLS file
			Workbook workbook = WorkbookFactory.create(file);

			// Get first sheet from the workbook
			Sheet sheet = workbook.getSheetAt(0);

			// Get iterator to all the rows in current sheet
			Iterator<Row> rowIterator = sheet.iterator();
			int rowIndex = 0;

			// TODO, set the first sector for the moment, later load and select
			String fileName = file.getName();
			formatedDate = DateUtil.getFormattedDate(fileName);

			// check file name
			if (!StockUtil.getFileName(fileName).equals(
					Constants.WEEKLY_SECTOR_DATA)) {
				returnData.setNo(Constants.ERROR);
				returnData.setMsg("Please add weekly sector data only");
				return returnData;
			}

			// check future date
			if (DateUtil.checkFutureDate(formatedDate)) {
				returnData.setNo(Constants.ERROR);
				returnData.setMsg("Please enter corrcet date");
				return returnData;
			}

			Criterion compleateCriterion = Restrictions.between("date",
					DateUtil.getWeekStart(formatedDate),
					DateUtil.getWeekEnd(formatedDate));

			List<BaseEntity> dataList = genericService.findByCriteria(
					compleateCriterion, WeeklySectorData.class);
			if (dataList.size() > 0) {
				processExsistingRecords(dataList);
			}

			while (rowIterator.hasNext()) {
				WeeklySectorData weeklySectorData = null;
				String sectorCode = null;
				double closingValue = 0.00;
				double noOfTrades = 0.00;
				double volume = 0.00;
				double turnOver = 0.00;
				double open = 0.00;
				double high = 0.00;
				double low = 0.00;

				Row row = rowIterator.next();
				// Get iterator to all cells of current row
				Iterator<Cell> cellIterator = row.cellIterator();

				if (rowIndex == 0) {
					Cell firstCell = row.getCell(0);
					if (firstCell == null) {
						returnData.setNo(Constants.ERROR);
						returnData
								.setMsg("Error file format, data should be started from first row and column");
						return returnData;
					}
					rowIndex++;
					continue;
				}

				int colIndex = 0;
				while (cellIterator.hasNext()) {
					Cell cell = cellIterator.next();
					Object cellVal = getCellValue(cell);
					switch (colIndex) {
					case 0:
						ReturnData<?> codeReturn = validateSectorCode(cellVal,
								rowIndex);
						if (codeReturn._isSuccess()) {
							sectorCode = (String) cellVal;
						} else {
							returnData.setNo(Constants.ERROR);
							returnData.setMsg(codeReturn.getMsg());
							return returnData;
						}
						break;
					case 1:
						volume = (Double) cellVal;
						break;

					case 2:
						noOfTrades = (Double) cellVal;
						break;

					case 3:
						turnOver = (Double) cellVal;
						break;

					case 4:
						high = (Double) cellVal;
						break;
					case 5:
						low = (Double) cellVal;
						break;
					case 6:
						closingValue = (Double) cellVal;
						break;
					case 7:
						open = (Double) cellVal;
						break;

					default:
						break;
					}

					colIndex++;
				}

				Sector sector = sectorMap.get(sectorCode);
				if (dataList.size() > 0) {
					Date dateFinal = formatedDate;
					Calendar callender = Calendar.getInstance();
					callender.setTime(formatedDate);
					String dateCode = getDataString(dateFinal);
					if (exsistingSectorDataMap.containsKey(sectorCode)) {
						if (exsistingSectorDataMap.containsKey(sectorCode)) {
							weeklySectorData = exsistingSectorDataMap
									.get(sectorCode);
						} else {
							weeklySectorData = new WeeklySectorData();
						}
					} else {
						weeklySectorData = new WeeklySectorData();
					}
				} else {
					weeklySectorData = new WeeklySectorData();
				}

				weeklySectorData.setSector(sectorMap.get(sectorCode));
				weeklySectorData.setClosingValue(closingValue);
				weeklySectorData.setNoOfTrades(noOfTrades);
				weeklySectorData.setTurnOver(turnOver);
				weeklySectorData.setVolume(volume);
				weeklySectorData.setDate(formatedDate);

				weeklySectorData.setOpen(open);
				weeklySectorData.setHigh(high);
				weeklySectorData.setLow(low);

				weeklySectorDataList.add(weeklySectorData);

				rowIndex++;
			}

			returnData.setData(weeklySectorDataList);

		} catch (IOException e) {
			e.printStackTrace();
			returnData.setNo(Constants.ERROR);
			returnData.setMsg(e.getMessage());
		} catch (InvalidFormatException e) {
			e.printStackTrace();
			returnData.setNo(Constants.ERROR);
			returnData.setMsg(e.getMessage());
		}

		return returnData;
	}

	private ReturnData<?> validateSectorCode(Object cellVal, int row) {
		ReturnData<String> returnData = new ReturnData<String>(
				Constants.SUCCESS, "");

		if (!validateForNull(cellVal)) {
			returnData.setNo(Constants.ERROR);
			returnData.setMsg("Sector code cannot be null at row " + row);
		}

		if (cellVal instanceof String) {
			String sectorCode = (String) cellVal;

			// TODO validate format - with regular expression ?

		} else {
			returnData.setNo(Constants.ERROR);
			returnData.setMsg("Sector code is in the wrong format at row "
					+ row);
		}

		return returnData;
	}

}
